#ifndef __EPSILON3D__SHADER_H__
#define __EPSILON3D__SHADER_H__

#include "../../Epsilon/Epsilon3D/OpenGL.h"
#include "../../Epsilon/file.h"

class eTB_Shader
{
friend class eTB_Program;
public:
  enum Type {
    Pixel    = 0x01,
    Vertex   = 0x02,
    Geometry = 0x04,
    Hull     = 0x08,
    Domain   = 0x10,
    Compute  = 0x20,

    Invalid  = 0x0
  } type_;

  eTB_Shader (const char* szName) {
    name_ = strdup (szName);
    type_ = Invalid;
  }

  virtual ~eTB_Shader (void) {
    if (name_ != NULL) {
      delete [] name_;
      name_ = NULL;
    }
  }

  virtual bool     Compile (void);
  virtual eStringA GetLog  (void);

  inline Type GetType (void) {
    return type_;
  }

  /* NOTE: When using GLSL, OpenGL also keeps a copy of the
             shader source code... consider re-visiting this
               issue when implementing Direct3D HLSL. */
  const char* source_;
  const char* name_;

protected:
  GLuint handle_;

//  int    ref_count_; /* Number of programs referencing the shader. */
};

class eTB_ShaderFactory {
public:
  eTB_Shader* createShaderFromFile ( const char*      szFileName,
                                     const char*      szName,
                                     eTB_Shader::Type type );

  /* Create a Shader from an Already Open File... */
  eTB_Shader* createShaderFromOpenFile ( eFile*           file,
                                         eFileSize        size,
                                         const char*      szName,
                                         eTB_Shader::Type type );

  eTB_Shader* createShaderFromString ( const char*      szSourceCode,
                                       const char*      szName,
                                       eTB_Shader::Type type );
};

class eTB_VertexShader : public eTB_Shader
{
friend class eTB_ShaderFactory;
private:
  eTB_VertexShader (const char* szName) : eTB_Shader (szName) {
    type_   = Vertex;
    handle_ = glCreateShader (GL_VERTEX_SHADER);
  }
};

class eTB_PixelShader : public eTB_Shader
{
friend class eTB_ShaderFactory;
private:
  eTB_PixelShader (const char* szName) : eTB_Shader (szName) {
    type_   = Pixel;
    handle_ = glCreateShader (GL_FRAGMENT_SHADER);
  }
};

#endif /* __EPSILON3D__SHADER_H__ */
